#pragma once

#include<iostream>
#include<string>
#include<functional>
#include<cstring>
#include<cassert>
#include<pthread.h>

class Thread;

class Context
{
public:
    Thread* this_;
    void* args_;

    Context()
        :this_(nullptr)
        ,args_(nullptr)
    {}

    ~Context()
    {}
};

class Thread
{
public:
    typedef std::function<void*(void*)> func_t;
    const int num=1024;

public:
    Thread(func_t func,void* args=nullptr,int number=0)
        :func_(func)
        ,args_(args)
    {
        char buffer[num];
        snprintf(buffer,sizeof buffer,"thread-%d",number);
        name_=buffer;
    }

    void* run(void* args)
    {
        return func_(args);
    }
    
    static void* start_routine(void* args)
    {
        Context* ctx=static_cast<Context*>(args);
        void* ret=ctx->this_->run(ctx->args_);
        delete ctx;
        return ret;
    }

    void start()
    {
        Context* ctx=new Context();
        ctx->this_=this;
        ctx->args_=args_;
        int n=pthread_create(&tid_,nullptr,start_routine,ctx);
        assert(n==0);
        (void)n;
    }

    void join()
    {
        int n=pthread_join(tid_,nullptr);
        assert(n==0);
        (void)n;
    }

    ~Thread()
    {}

private:
    std::string name_;
    func_t func_;
    void* args_;
    pthread_t tid_;
};